package jmine.tec.test.utils.spring;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;

import org.springframework.beans.factory.ListableBeanFactory;

/**
 * Injeta de uma {@link ListableBeanFactory} em um bean
 * 
 * @author takeshi
 */
public class PropertiesInjector {

    private final ListableBeanFactory listableBeanFactory;

    /**
     * @param listableBeanFactory {@link ListableBeanFactory}
     */
    public PropertiesInjector(ListableBeanFactory listableBeanFactory) {
        super();
        this.listableBeanFactory = listableBeanFactory;
    }

    /**
     * @param object Object
     */
    public void autowire(Object object) {
        autowireFields(object, object.getClass());
    }

    /**
     * @param object object
     * @param type type
     */
    private void autowireFields(final Object object, Class<?> type) {
        if (type == null || type == Object.class) {
            return;
        }
        Field[] declaredFields = type.getDeclaredFields();
        for (final Field field : declaredFields) {
            if (Modifier.isFinal(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) {
                continue;
            }
            final String name = field.getName();
            if (listableBeanFactory.containsBean(name)) {
                Class<?> concreteType = listableBeanFactory.getType(name);
                if (field.getType().isAssignableFrom(concreteType)) {
                    try {
                        AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
                            public Void run() throws Exception {
                                field.setAccessible(true);
                                field.set(object, listableBeanFactory.getBean(name));
                                return null;
                            }
                        });
                    } catch (Exception e) {
                        System.err.println(e.getMessage());
                    }
                }
            }
        }
        autowireFields(object, type.getSuperclass());
    }

}
